# -*- coding: utf-8 -*-
import datetime
import webapp2
import os
import jinja2
import json
import re
import math
from google.appengine.api import taskqueue
from google.appengine.ext import db
from google.appengine.api import users
from google.appengine.api import urlfetch
from google.appengine.api import mail
#from webapp2_extras.appengine.users import login_required
# 数据库模型
from model.dbModels import AreaInfo, Subscriber, ScheduledList

# Template Environment
jj2 = jinja2.Environment(
     loader=jinja2.FileSystemLoader(os.path.join(os.path.dirname(__file__)
                                                 ,'template')))

def fetchJson(url):
    '''抓取json编码页面并解码'''
    result = urlfetch.fetch(url)
    if result.status_code == 200:
        return json.loads(result.content)

class BeijingTZ(datetime.tzinfo):
    '''北京时间的tzinfo实现'''
    
    def utcoffset(self, dt):
        return datetime.timedelta(hours=8)

    def dst(self, dt):
        return datetime.timedelta(0)

    def tzname(self, dt):
        return 'CST'

class UTC(datetime.tzinfo):
    """UTC"""

    def utcoffset(self, dt):
        return datetime.timedelta(0)

    def tzname(self, dt):
        return "UTC"

    def dst(self, dt):
        return datetime.timedelta(0)
    
class MainPage(webapp2.RequestHandler):
    
    def get(self):
        tpl_vals = {}
        user = users.get_current_user()
        if user is None:
            tpl_vals['login'] = users.create_login_url('/')
            tpl = 'main.html'
        else:
            tpl_vals['logout'] = users.create_logout_url('/')
            tpl = 'subscribe.html'
            #订阅信息
            suber = db.GqlQuery("SELECT __key__ FROM Subscriber WHERE account = :1", 
                                user).get()
            sched_list = []
            if suber:
                scheds = ScheduledList.gql("WHERE ANCESTOR IS :1 ORDER BY created DESC", 
                                           suber)
                
                for sched in scheds:
                    sched_list.append(self._get_sched_data(sched))
            
            tpl_vals['scheds'] = sched_list
        template = jj2.get_template(tpl)
        self.response.out.write(template.render(tpl_vals))

    def _get_sched_data(self, s):
        r = {}
        r['key'] = s.key()
        r['city'] = s.area.name
        r['email'] = s.email
        r['timing'] = s.timing.strftime('%I:%M%p')
        r['created'] = s.created.replace(tzinfo=UTC()).astimezone(BeijingTZ()).strftime("%y/%m/%d %H:%M") 
        return r        

class Schedule(webapp2.RequestHandler):
    def post(self, do):
        if do == 'delete':
            db.delete(self.request.get("key", allow_multiple=True))
        elif do == 'add':
            self.add()
        
        self.redirect('/')

    def add(self):
        area = self.request.get('area')
        code = self.request.get('code')
        email = self.request.get('email')
        timing = [int(x) for x 
                  in self.request.get('timing').split(':') if x.isdigit()]
        user = users.get_current_user()

        if (('' in [area, code, email]) or not code.isdigit()
            or not mail.is_email_valid(email) or not len(timing)
            or user is None):
            self.abort(403)
        #TODO: 改成事务处理
        area_info = AreaInfo(name=area, code=code).get_or_put()
        suber = Subscriber(account=user).get_or_put()

        sched = ScheduledList(parent=suber)
        sched.area = area_info
        sched.email = email
        sched.timing = datetime.time(*timing)
        sched.put()

class WeatherMan(webapp2.RequestHandler):
    '''天气预报控制器
    天气预报信息将以邮件形式发出，但因邮件配额限制（8/m）使用了task queue。支持最小预报
    间隔是30m。所以设定task cron可以设定时间为整点或半点。
    '''
    # weather api
    api_6days = 'http://m.weather.com.cn/data/%s.html'
    api_now = 'http://www.weather.com.cn/data/sk/%s.html'
    
    # 天气模板
    tpl_6days = 'mail_6days.tpl'
    
    # 天气信息缓存，以dict数据形式
    tpl_temp = {}
    
    def get(self, *args):
        scheds = self._scheduledList()
        times = math.ceil(float(scheds.count())/8)
        i = 0
        while i<times:
            keys = [str(x) for x in scheds[i*8:(i+1)*8]]
            taskqueue.add(url='/weather', 
                          params={'keys': keys},
                          queue_name='mail-queue')
            i += 1
    
    def post(self, *args):
        keys = self.request.get_all('keys')
        
        if not keys or not isinstance(keys, (list, tuple)):
            self.abort(403)
        scheds = db.Model.get(keys)
        for sched in scheds:
            self._mailer(sched)

    def _fetch6days(self, cityid):
        '''获得6天内天气数据'''
        sixdays = fetchJson(self.api_6days % cityid)
        now = fetchJson(self.api_now % cityid)
        if sixdays and now:
            data = {'now': now["weatherinfo"],
                    'sixdays': sixdays["weatherinfo"]}
            
            t = re.findall(r'\d+', sixdays["weatherinfo"]["date_y"])
            y = datetime.date(*[int(x) for x in t])
            # 6天日期列表            
            data['daylist'] = [y+datetime.timedelta(x) for x in range(0,6)]
            data['sysdate'] = datetime.datetime.now(BeijingTZ()).date()
            return data
    
    def _fetchNow(self, cityid):
        '''获得当天实时数据'''
        url = self.api_now % cityid
        return fetchJson(url)
    
    def _scheduledList(self):
        '''获取天气预报计划任务'''
        #本地时间中小时位数
        now = datetime.datetime.now(BeijingTZ())
        
        return db.GqlQuery("SELECT __key__ FROM ScheduledList WHERE timing=:1 ORDER BY area", 
                           datetime.time(now.hour,
                                         int(float(now.minute)/30)*30))
            
    def _getContent(self, cityid):
        '''获取天气内容'''
        if not cityid in self.tpl_temp:
            data = self._fetch6days(cityid) 
            self.tpl_temp[cityid] = jj2.get_template(self.tpl_6days).render(data)
        
        return self.tpl_temp[cityid]
    
    def _mailer(self,sched):
        '''发送预定邮件'''
        user_address = sched.email
        
        if not mail.is_email_valid(user_address):
            return None
        # prompt user to enter a valid address
        app_id = os.environ['APPLICATION_ID']
        app_id = app_id[app_id.find('~')+1:]
        sender_address = "WeatherMan <noreply@%s.appspotmail.com>" % app_id
        subject = sched.area.name
        body = self._getContent(sched.area.code)

        mail.send_mail(sender_address, user_address, subject, body)

#===============================================================================
# WSGI-compliant应用全局对象，由GAE调用
#===============================================================================
app = webapp2.WSGIApplication([('/', MainPage),
                               ('/weather', WeatherMan),
                               webapp2.Route(r'/schedule/<do:\w+>', handler=Schedule, name='schedule-do'),],
                              debug=True)
